package com.hanxiaozhang.no10leetcode.array;

/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 * 给定一个数组，其中第i个元素代表了第i天的股票价格，设计一个算法找到最大收益，最多只能进行两次交易
 * 注意：不能同时操作多个交易(再次交易前必须将手里的股票卖出去)
 * 示例 1:
 * 输入：prices = [3,3,5,0,0,3,1,4]
 * 输出：6
 * 解释：在第4天（股票价格 = 0）的时候买入，在第6天（股票价格 = 3）的时候卖出，这笔交易所能获得利润=3-0=3。
 * 随后，在第7天（股票价格 = 1）的时候买入，在第8天（股票价格 = 4）的时候卖出，这笔交易所能获得利润=4-1=3。
 * <p>
 * 示例 2：
 * 输入：prices = [1,2,3,4,5]
 * 输出：4
 * 解释：在第1天（股票价格 = 1）的时候买入，在第5天（股票价格 = 5）的时候卖出, 这笔交易所能获得利润=5-1=4。
 * 注意你不能在第1天和第2天接连购买股票，之后再将它们卖出。因为这样属于同时参与了多笔交易，
 * 你必须在再次购买前出售掉之前的股票。
 * <p>
 * 示例 3：
 * 输入：prices = [7,6,4,3,1]
 * 输出：0
 * 解释：在这个情况下, 没有交易完成, 所以最大利润为 0。
 * <p>
 * 示例 4：
 * 输入：prices = [1]
 * 输出：0
 *
 * @author hanxinghua
 * @create 2024/1/29
 * @since 1.0.0
 */
public class No123BestTimeTradeStockIII {


    public static void main(String[] args) {

        int[] prices = {3, 3, 5, 0, 0, 3, 1, 4};

        System.out.println(maxProfit(prices));

    }


    /**
     * 因为一次不能操作多个交易，那么第二次交易是不是可以理解为也是一次单独的交易，只不过要在第一次之后，
     * 第二次和第一次交易区别在哪里？
     * 找最大值的方法肯定没有区别，因为都是一次交易嘛，但是关键是第二次交易的时候你要计算的买入价格不一样了，
     * 因为通过第一次交易，你已经存在收益了，所以我再买的话，我起始金额不再是0了。
     * 举例：第一次交易挣了一万块，然后你决定再接再厉，再买一万五的，这个第二次投资其实相当于你目前现金流里只少了五千块，
     * 因为，你这次是带着收益再次进入股市的。
     * 计算第二次购买股票的起始价格时，不能是像第一次一样，比较当前值和最小值中的较小值了，
     * 而是比较当前值减去第一次收益之后和最小值去比得到更小值。
     * 计算第二次收益没有区别，还是当前值减去你二次购买的起始值就是收益，但是，这个收益值其实是包含了你第一次收益在内的最大收益，
     * 所以遍历数组之后，最后得到的值就是最多两次交易后的最大值。
     *
     * @param prices
     * @return
     */
    public static int maxProfit(int[] prices) {
        // 第一次购买值时，最低价格
        int buyFirstMin = Integer.MAX_VALUE;
        // 第二次购买值时，最低价格（这里需要减去第一次的例如）
        int buySecondMin = Integer.MAX_VALUE;
        // 第一次出售值时，最大利润
        int sellFirstProfitMax = 0;
        // 第二次出售值是，最大利润
        int sellSecondProfitMax = 0;
        for (int p : prices) {
            buyFirstMin = Math.min(buyFirstMin, p);
            sellFirstProfitMax = Math.max(sellFirstProfitMax, p - buyFirstMin);
            buySecondMin = Math.min(buySecondMin, p - sellFirstProfitMax);
            sellSecondProfitMax = Math.max(sellSecondProfitMax, p - buySecondMin);
        }
        return sellSecondProfitMax;
    }

}
